﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using PSE.Deployment.ConfigurationManager.Controls;
using PSE.Deployment.ConfigurationManager.Engine.Operations;
using PSE.Deployment.SetupBase;
using PSE.Deployment.SetupBase.Configuration;
using PSE.Deployment.SetupBase.Configuration.Actions;
using PSE.Deployment.SetupBase.Parameter;
using PSE.Deployment.Util;
using System.Windows.Threading;

namespace PSE.Deployment.ConfigurationManager.UI
{
    public abstract class WindowBase : Window
    {
        Grid PART_LoadingPanel;
        ScreenTitle PART_ScreenTitle;
        TreeView PART_mainTreeView;
        Border PART_contentPresenter;

        const int GRID_STARTING_LINE = 1;
        List<TreeViewItemBase> _mainTreeViewItems = null;
        ServiceTreeViewItem _installedServices = null;
        XmlOperations _xmlOperations = null;
        RegistryOperations _registryOperations = null;
        SetupParameter _param;
        string _parametersFilePath;
        protected virtual string SystemId { get { return "Setup"; } }

        public WindowBase()
        {
            this.SetResourceReference(WindowBase.StyleProperty, "WindowBaseStyle");
            this.WindowStartupLocation = WindowStartupLocation.CenterScreen;

            PSE.Deployment.Util.WindowsRegistry.InstalledInformation information = PSE.Deployment.Util.WindowsRegistry.GetInstalledInformation(SystemId);

            if (information != null)
                _parametersFilePath = information.ParametersFilePath;

            ChangeIcon();
        }

        public bool CheckSystemInstallation()
        {
            if (!PSE.Deployment.Util.WindowsRegistry.HasInstalledInformation(SystemId))
            {
                ConfigurationMessageBox.Show("Não foi possível iniciar o aplicativo de configuração.\nO sistema \"" + SystemId + "\" não está instalado.");
                return false;
            }
            return true;
        }
        protected List<UpdateConfig> Configs
        {
            get
            {
                List<UpdateConfig> configs = new List<UpdateConfig>();

                foreach (TreeViewItemBase groupTv in _mainTreeViewItems)
                {
                    if (groupTv is GroupTreeViewItem)
                        this.RetrieveAllUpdateConfigs(((GroupTreeViewItem)groupTv).Group, configs);
                }

                return configs;
            }
        }
        protected List<RegistryKey> RegistryKeys
        {
            get
            {
                List<RegistryKey> registryKeys = new List<RegistryKey>();

                foreach (TreeViewItemBase groupTv in _mainTreeViewItems)
                {
                    if (groupTv is GroupTreeViewItem)
                        this.RetrieveAllRegistryFiles(((GroupTreeViewItem)groupTv).Group, registryKeys);
                }

                return registryKeys;
            }
        }
        protected virtual bool IsDataBaseInstalledCorrectly
        {
            get { return false; }
        }
        protected string WindowTitle
        {
            get { return base.Title; }
            set { base.Title = value; }
        }

        void mainTreeView_SelectedItemChanged(object sender, RoutedPropertyChangedEventArgs<object> e)
        {
            object selectedItem = (((TreeView)sender).SelectedItem);
            this.LoadCustomControlGrid(selectedItem);
        }

        void PART_SaveButton_Click(object sender, RoutedEventArgs e)
        {
            try
            {
                if (ConfigurationMessageBox.Show("Deseja realmente salvar as alterações?", ConfigurationMessageBoxButton.YesNo, ConfigurationMessageBoxImage.Question) == ConfigurationMessageBoxResult.Yes)
                {
                    if (this.ValidateControls())
                    {
                        this.ChangeLoadingPanelVisibility(true);

                        SaveResult r = SaveConfiguration();

                        switch (r.Result)
                        {
                            case SaveResultOptions.SavedWithoutServiceChanges:
                                PSE.Deployment.ConfigurationManager.Controls.ConfigurationMessageBox.Show("Alterações Salvas com sucesso.", ConfigurationMessageBoxButton.Ok, ConfigurationMessageBoxImage.Information);
                                break;
                            case SaveResultOptions.SavedWithServiceChanges:
                                StringBuilder sb = new StringBuilder();
                                if (r.ServicesWhoNeedsRestart != null && r.ServicesWhoNeedsRestart.Count > 0)
                                {
                                    foreach (string s in r.ServicesWhoNeedsRestart)
                                    {
                                        sb.AppendLine(" - " + s);
                                    }
                                }
                                PSE.Deployment.ConfigurationManager.Controls.ConfigurationMessageBox.Show(String.Format("Alterações Salvas com sucesso.\n\nPara que suas alterações tenham efeito você deverá reiniciar os seguintes serviços:\n\n{0}", sb.ToString()), ConfigurationMessageBoxButton.Ok, ConfigurationMessageBoxImage.Information);
                                break;
                            case SaveResultOptions.NotSaved:
                                PSE.Deployment.ConfigurationManager.Controls.ConfigurationMessageBox.Show("Nenhuma alteração realizada.", ConfigurationMessageBoxButton.Ok, ConfigurationMessageBoxImage.Information);
                                break;
                        }

                        this.ChangeLoadingPanelVisibility(false);
                    }
                    else
                    {
                        ConfigurationMessageBox.Show("Existem campos inválidos, corriga as informações antes de salvar as alterações.", ConfigurationMessageBoxButton.Ok, ConfigurationMessageBoxImage.Exclamation);
                    }
                }
            }
            catch
            {
                this.ChangeLoadingPanelVisibility(false);
            }            
        }

        //-------------------------------------------------------------------------------------------------------

        void LoadCustomControlGrid(object selectedItem)
        {
            StackPanel controlGrid = new StackPanel();

            //ColumnDefinition colLabel = new ColumnDefinition();
            //ColumnDefinition colControl = new ColumnDefinition();

            //colLabel.Width = GridLength.Auto;
            //colControl.Width = new GridLength(1, GridUnitType.Star);

            //controlGrid.ColumnDefinitions.Add(colLabel);
            //controlGrid.ColumnDefinitions.Add(colControl);

            //RowDefinition descriptionRow = new RowDefinition();
            //descriptionRow.Height = new GridLength(40, GridUnitType.Pixel);

            //controlGrid.RowDefinitions.Add(descriptionRow);

            if (selectedItem is XmlFileTreeViewItem)
                this.LoadXmlFileControlGrid(selectedItem as XmlFileTreeViewItem, controlGrid);
            else if (selectedItem is RegistryKeyTreeViewItem)
                this.LoadRegistryKeyControlGrid(selectedItem as RegistryKeyTreeViewItem, controlGrid);
            else if (selectedItem is ServiceTreeViewItem)
                this.LoadServicesControlGrid(selectedItem as ServiceTreeViewItem, controlGrid);
        }

        void LoadXmlFileControlGrid(XmlFileTreeViewItem selectedItem, StackPanel controlGrid)
        {
            if (selectedItem != null)
            {
                XmlFileTreeViewItem xmlFile = (XmlFileTreeViewItem)selectedItem;

                this.PART_ScreenTitle.Header = xmlFile.Xml.Title;
                SimpleLabel descriptionLabel = new SimpleLabel(xmlFile.Xml.Description, HorizontalAlignment.Left, VerticalAlignment.Center, Brushes.Black, 14);

                //descriptionLabel.SetValue(Grid.RowProperty, 0);
                //descriptionLabel.SetValue(Grid.ColumnSpanProperty, 2);
                descriptionLabel.Height = Double.NaN;
                descriptionLabel.Width = Double.NaN;
                descriptionLabel.HorizontalAlignment = HorizontalAlignment.Left;
                descriptionLabel.HorizontalContentAlignment = HorizontalAlignment.Left;
                descriptionLabel.Margin = new Thickness(10, 0, 0, 0);

                controlGrid.Children.Add(descriptionLabel);

                if (xmlFile.Xml.Tags != null && xmlFile.Xml.Tags.Count > 0)
                {
                    int gridRowCounter = GRID_STARTING_LINE;

                    List<XmlTag> tagsUpdate = xmlFile.Xml.Tags.FindAll(tag => tag.OperationType == PSE.Deployment.SetupBase.Configuration.Enums.XmlTagOperationType.Update);
                    List<XmlTag> tagsInsert = xmlFile.Xml.Tags.FindAll(tag => tag.OperationType == PSE.Deployment.SetupBase.Configuration.Enums.XmlTagOperationType.Insert);

                    foreach (XmlTag tag in tagsUpdate)
                    {
                        if (tag.IsVisible)
                        {
                            //RowDefinition itemRow = new RowDefinition();
                            //itemRow.Height = new GridLength(25, GridUnitType.Pixel);

                            //controlGrid.RowDefinitions.Add(itemRow);

                            SimpleLabel label = new SimpleLabel(tag.Description, HorizontalAlignment.Left, VerticalAlignment.Center);
                            label.Margin = new Thickness(10, 0, 0, 0);

                            Control customControl = null;

                            if (tag.IsList)
                                customControl = this.RetrieveComboBoxControl(tag, "Item", "Value");
                            else
                                customControl = this.RetrieveCustomControl(tag);

                            if (customControl != null)
                            {
                                this.AddCustomControl(label, customControl, controlGrid, gridRowCounter);
                                gridRowCounter++;
                            }
                        }
                    }

                    if (tagsInsert != null && tagsInsert.Count > 0)
                    {
                        //RowDefinition itemRow = new RowDefinition();
                        //itemRow.Height = new GridLength(1, GridUnitType.Auto);

                        //controlGrid.RowDefinitions.Add(itemRow);

                        FrameworkElement customControl = new SimpleGroupBoxes(xmlFile.Xml.Tags, tagsInsert);

                        if (customControl != null)
                        {
                            this.AddCustomControl(customControl, controlGrid, gridRowCounter);
                            gridRowCounter++;
                        }
                    }
                }

                SimpleScrollViewer scrollViewer = new SimpleScrollViewer();
                scrollViewer.Content = controlGrid;

                PART_contentPresenter.Child = scrollViewer;
            }
        }

        void LoadRegistryKeyControlGrid(RegistryKeyTreeViewItem selectedItem, StackPanel controlGrid)
        {
            if (selectedItem != null)
            {
                RegistryKeyTreeViewItem regKey = (RegistryKeyTreeViewItem)selectedItem;

                this.PART_ScreenTitle.Header = regKey.Registry.Title;
                SimpleLabel descriptionLabel = new SimpleLabel(regKey.Registry.Description, HorizontalAlignment.Left, VerticalAlignment.Center, Brushes.Black, 14);

                //descriptionLabel.SetValue(Grid.RowProperty, 0);
                //descriptionLabel.SetValue(Grid.ColumnSpanProperty, 2);
                descriptionLabel.Height = Double.NaN;
                descriptionLabel.Width = Double.NaN;
                descriptionLabel.HorizontalAlignment = HorizontalAlignment.Left;
                descriptionLabel.HorizontalContentAlignment = HorizontalAlignment.Left;
                descriptionLabel.Margin = new Thickness(10, 0, 0, 0);

                controlGrid.Children.Add(descriptionLabel);

                if (regKey.Registry.Values != null && regKey.Registry.Values.Count > 0)
                {
                    int gridRowCounter = GRID_STARTING_LINE;

                    foreach (RegistryValue regValue in regKey.Registry.Values)
                    {
                        if (regValue.IsVisible)
                        {
                            //RowDefinition itemRow = new RowDefinition();
                            //itemRow.Height = new GridLength(25, GridUnitType.Pixel);

                            //controlGrid.RowDefinitions.Add(itemRow);

                            SimpleLabel label = new SimpleLabel(regValue.Description, HorizontalAlignment.Left, VerticalAlignment.Center);
                            label.Margin = new Thickness(10, 0, 0, 0);

                            Control customControl = null;

                            customControl = this.RetrieveCustomControl(regValue);

                            if (customControl != null)
                            {
                                this.AddCustomControl(label, customControl, controlGrid, gridRowCounter);
                                gridRowCounter++;
                            }
                        }
                    }
                }

                SimpleScrollViewer scrollViewer = new SimpleScrollViewer();
                scrollViewer.Content = controlGrid;

                PART_contentPresenter.Child = scrollViewer;
            }
        }

        void LoadServicesControlGrid(ServiceTreeViewItem selectedItem, StackPanel controlGrid)
        {
            if (selectedItem != null)
            {
                ServiceTreeViewItem serviceItem = (ServiceTreeViewItem)selectedItem;

                this.PART_ScreenTitle.Header = serviceItem.Header;
                SimpleLabel descriptionLabel = new SimpleLabel(serviceItem.Description, HorizontalAlignment.Left, VerticalAlignment.Center, Brushes.Black, 14);

                //descriptionLabel.SetValue(Grid.RowProperty, 0);
                //descriptionLabel.SetValue(Grid.ColumnSpanProperty, 2);
                descriptionLabel.Height = Double.NaN;
                descriptionLabel.Width = Double.NaN;
                descriptionLabel.HorizontalAlignment = HorizontalAlignment.Left;
                descriptionLabel.HorizontalContentAlignment = HorizontalAlignment.Left;
                descriptionLabel.Margin = new Thickness(10, 0, 0, 0);

                controlGrid.Children.Add(descriptionLabel);

                if (serviceItem.InstalledServices != null && serviceItem.InstalledServices.Count > 0)
                {
                    int radioButtonGroupNumber = 0;
                    int gridRowCounter = GRID_STARTING_LINE;

                    foreach (PSE.Deployment.SetupBase.Configuration.WindowsService windowsService in serviceItem.InstalledServices)
                    {
                        //RowDefinition itemRow = new RowDefinition();
                        //itemRow.Height = GridLength.Auto;//new GridLength(30, GridUnitType.Pixel);
                        //itemRow.MinHeight = Convert.ToDouble(30);

                        //controlGrid.RowDefinitions.Add(itemRow);

                        ServiceControl serv = CreateServiceControl(windowsService);

                        this.AddCustomControl(serv, controlGrid, gridRowCounter);

                        radioButtonGroupNumber++;
                        gridRowCounter++;
                    }
                }

                SimpleScrollViewer scrollViewer = new SimpleScrollViewer();
                scrollViewer.Content = controlGrid;

                PART_contentPresenter.Child = scrollViewer;
            }
        }

        /// <summary>
        /// Criar um ServiceControl, método pode ser sobrescrito para criar um controle customizado
        /// </summary>
        /// <param name="windowsService"></param>
        /// <returns></returns>
        protected virtual ServiceControl CreateServiceControl(PSE.Deployment.SetupBase.Configuration.WindowsService windowsService)
        {
            ServiceControl serv = new ServiceControl(windowsService);
            return serv;
        }

        void AddCustomControl(SimpleLabel label, Control customControl, StackPanel controlGrid, int gridRowCounter)
        {
            if (customControl is SimpleCheckBox)
            {
                Grid grid = new Grid();
                
                ColumnDefinition colControl = new ColumnDefinition();
                ColumnDefinition colLabel = new ColumnDefinition();

                colControl.Width = GridLength.Auto;
                colLabel.Width = GridLength.Auto;
                grid.Width = double.NaN;

                grid.ColumnDefinitions.Add(colControl);
                grid.ColumnDefinitions.Add(colLabel);

                RowDefinition itemRow = new RowDefinition();
                itemRow.Height = GridLength.Auto;
                itemRow.MinHeight = Convert.ToDouble(30);

                grid.RowDefinitions.Add(itemRow);

                customControl.SetValue(Grid.HorizontalAlignmentProperty, HorizontalAlignment.Left);
                customControl.Margin = new Thickness(15, 0, 0, 0);
                customControl.SetValue(Grid.VerticalAlignmentProperty, VerticalAlignment.Center);
                customControl.SetValue(Grid.RowProperty, 0);
                customControl.SetValue(Grid.ColumnProperty, 0);
                grid.Children.Add(customControl);

                label.SetValue(Grid.RowProperty, 0);
                label.SetValue(Grid.ColumnProperty, 1);
                label.SetValue(Grid.HorizontalAlignmentProperty, HorizontalAlignment.Left);
                label.Margin = new Thickness(0, 0, 0, 0);
                grid.Children.Add(label);

                controlGrid.Children.Add(grid);
            }
            else
            {
                controlGrid.Children.Add(label);
                customControl.SetValue(Grid.HorizontalAlignmentProperty, HorizontalAlignment.Left);
                customControl.Margin = new Thickness(15, 0, 0, 0);
                customControl.SetValue(Grid.VerticalAlignmentProperty, VerticalAlignment.Center);
                controlGrid.Children.Add(customControl);
            }
        }

        void AddCustomControl(FrameworkElement customControl, StackPanel controlGrid, int gridRowCounter)
        {
            customControl.SetValue(Grid.VerticalAlignmentProperty, VerticalAlignment.Center);
            customControl.SetValue(Grid.HorizontalAlignmentProperty, HorizontalAlignment.Left);
            customControl.Margin = new Thickness(15, 0, 0, 0);
            controlGrid.Children.Add(customControl);
        }

        void LoadDenpendencies(List<Group> groups, Dictionary<string, Group> dependencyGroups, bool isDependency)
        {
            foreach (Group g in groups)
            {
                if (g.Dependencies != null && g.Dependencies.Count > 0)
                {
                    LoadDenpendencies(g.Dependencies, dependencyGroups, true);
                }

                if (g.SubGroups != null && g.SubGroups.Count > 0)
                {
                    LoadDenpendencies(g.SubGroups, dependencyGroups, false);
                }

                if (g.Installed && isDependency && !dependencyGroups.ContainsKey(g.Id))
                {
                    dependencyGroups.Add(g.Id, g);
                }
            }
        }

        void RetrieveAllUpdateConfigs(Group g, List<UpdateConfig> configs)
        {
            foreach (ActionBase action in g.Actions)
            {
                if (action is UpdateConfig)
                {
                    configs.Add((UpdateConfig)action);
                }
            }

            if (g.SubGroups != null && g.SubGroups.Count > 0)
            {
                foreach (Group group in g.SubGroups)
                    this.RetrieveAllUpdateConfigs(group, configs);
            }
        }

        void RetrieveAllRegistryFiles(Group g, List<RegistryKey> regKeys)
        {
            foreach (ActionBase action in g.Actions)
            {
                if (action is UpdateWindowsRegistry)
                {
                    foreach (RegistryKey regKey in ((UpdateWindowsRegistry)action).Keys)
                        regKeys.Add(regKey);
                }
            }

            if (g.SubGroups != null && g.SubGroups.Count > 0)
            {
                foreach (Group group in g.SubGroups)
                    this.RetrieveAllRegistryFiles(group, regKeys);
            }
        }

        Control DecideCustomControl(XmlTag tag)
        {
            switch (tag.Type)
            {
                case PSE.Deployment.SetupBase.Configuration.Enums.XmlTagType.String:
                    return new SimpleTextBox(tag);
                case PSE.Deployment.SetupBase.Configuration.Enums.XmlTagType.Uri:
                    return new UriTextBox(tag);
                case PSE.Deployment.SetupBase.Configuration.Enums.XmlTagType.Endpoint:
                    return new EndPointTextBox(tag);
                case PSE.Deployment.SetupBase.Configuration.Enums.XmlTagType.EndpointPort:
                    return new Int32TextBox(tag);
                case PSE.Deployment.SetupBase.Configuration.Enums.XmlTagType.Integer:
                    return new Int32TextBox(tag);
                case PSE.Deployment.SetupBase.Configuration.Enums.XmlTagType.Password:
                    return new PasswordTextBox(tag);
                case PSE.Deployment.SetupBase.Configuration.Enums.XmlTagType.Boolean:
                    return new SimpleCheckBox(tag);
                case PSE.Deployment.SetupBase.Configuration.Enums.XmlTagType.FilePath:
                    return new FilePathTextBox(tag);
                case PSE.Deployment.SetupBase.Configuration.Enums.XmlTagType.FolderPath:
                    return new FolderPathTextBox(tag);
                default:
                    return new SimpleTextBox(tag);
            }
        }

        Control DecideCustomControl(RegistryValue key)
        {
            switch (key.Type)
            {
                case PSE.Deployment.SetupBase.Configuration.Enums.XmlTagType.String:
                    return new SimpleTextBox(key);
                case PSE.Deployment.SetupBase.Configuration.Enums.XmlTagType.Uri:
                    return new UriTextBox(key);
                case PSE.Deployment.SetupBase.Configuration.Enums.XmlTagType.Endpoint:
                    return new EndPointTextBox(key);
                case PSE.Deployment.SetupBase.Configuration.Enums.XmlTagType.EndpointPort:
                    return new Int32TextBox(key);
                case PSE.Deployment.SetupBase.Configuration.Enums.XmlTagType.Integer:
                    return new Int32TextBox(key);
                case PSE.Deployment.SetupBase.Configuration.Enums.XmlTagType.Password:
                    return new PasswordTextBox(key);
                case PSE.Deployment.SetupBase.Configuration.Enums.XmlTagType.Boolean:
                    return new SimpleCheckBox(key);
                default:
                    return new SimpleTextBox(key);
            }
        }

        Control RetrieveCustomControl(XmlTag tag)
        {
            Control customControl = null;
            customControl = this.DecideCustomControl(tag);
            return customControl;
        }

        Control RetrieveCustomControl(RegistryValue key)
        {
            Control customControl = null;
            customControl = this.DecideCustomControl(key);
            return customControl;
        }

        Control RetrieveComboBoxControl(XmlTag tag, string displayMemberPath, string selectedValuePath)
        {
            Control customControl = null;

            if (this.IsDataBaseInstalledCorrectly && !(String.IsNullOrEmpty(tag.SQLCommand)))
            {
                customControl = new SimpleComboBox(tag, this.RetrieveQuery(tag.SQLCommand), displayMemberPath, selectedValuePath, tag.Value);
            }
            else if (tag.ControlItemSource.Count > 0)
            {
                customControl = new SimpleComboBox(tag, this.RetrieveDataSource(tag.ControlItemSource), displayMemberPath, selectedValuePath, tag.Value);
            }

            return customControl;
        }

        bool DisplayGroup(GroupTreeViewItem item, Group g)
        {
            return ((item.IsOnUpdateGroup || item.HasUpdateConfigInsideSubGroup) && g.Installed);
        }

        GroupTreeViewItem AddGroupToTreeView(Group g, GroupTreeViewItem parentTreeViewItem)
        {
            GroupTreeViewItem tvItem = new GroupTreeViewItem(g.Name, false, parentTreeViewItem, g);

            if (g.Actions != null && g.Actions.Count > 0)
            {
                foreach (ActionBase action in g.Actions)
                {
                    bool isUpdateConfigAction = ((action is UpdateConfig) || (action is UpdateWindowsRegistry));
                    bool hasSubGroups = ((g.SubGroups != null && g.SubGroups.Count > 0));

                    if (!tvItem.IsOnUpdateGroup)
                        tvItem.IsOnUpdateGroup = isUpdateConfigAction;

                    if (action is UpdateConfig)
                    {
                        UpdateConfig updConfig = (UpdateConfig)action;
                        if (updConfig.XmlFiles != null && updConfig.XmlFiles.Count > 0)
                        {
                            foreach (XmlFile xml in updConfig.XmlFiles)
                            {
                                if (xml.Tags != null && xml.Tags.Count > 0)
                                {
                                    _xmlOperations.DecryptTags(xml.Tags);

                                    if (xml.HasAnyVisibleTag)
                                        tvItem.Children.Add(new XmlFileTreeViewItem(xml, tvItem));
                                }
                            }

                            tvItem.IsOnUpdateGroup = tvItem.Children.Count > 0;
                        }
                        else
                        {
                            tvItem.IsOnUpdateGroup = false;
                        }
                    }
                    else if (action is UpdateWindowsRegistry)
                    {
                        UpdateWindowsRegistry updWindowsRegistry = (UpdateWindowsRegistry)action;
                        if (updWindowsRegistry.Keys != null && updWindowsRegistry.Keys.Count > 0)
                        {
                            foreach (RegistryKey key in updWindowsRegistry.Keys)
                            {
                                if (key.Values != null && key.Values.Count > 0)
                                {
                                    _registryOperations.DecryptTags(key.Values);

                                    if (key.HasAnyVisibleValue)
                                        tvItem.Children.Add(new RegistryKeyTreeViewItem(key, tvItem));
                                }
                            }

                            tvItem.IsOnUpdateGroup = tvItem.Children.Count > 0;
                        }
                        else
                        {
                            tvItem.IsOnUpdateGroup = false;
                        }
                    }
                }
            }

            if (g.SubGroups != null && g.SubGroups.Count > 0)
            {
                foreach (Group group in g.SubGroups)
                {
                    GroupTreeViewItem childItem = this.AddGroupToTreeView(group, tvItem);
                    if (childItem != null && DisplayGroup(childItem, group))
                        tvItem.Children.Add(childItem);
                }
            }

            return tvItem;
        }

        List<TreeViewItemBase> RetrieveGroups()
        {
            _param = (SetupParameter)PSE.Deployment.Util.Serializer.Deserialize(GetParameterType(), _parametersFilePath);

            _mainTreeViewItems = new List<TreeViewItemBase>();
            _installedServices = this.RetrieveInstalledServices();

            if (_param != null && _param.SetupConfiguration != null && _param.SetupConfiguration.SystemInfo != null && _param.SetupConfiguration.SystemInfo.Groups != null)
            {
                _xmlOperations = new XmlOperations(_param);
                _registryOperations = new RegistryOperations(_param);

                foreach (Group g in _param.SetupConfiguration.SystemInfo.Groups)
                {
                    GroupTreeViewItem item = this.AddGroupToTreeView(g, null);
                    if (item != null && this.DisplayGroup(item, g))
                    {
                        item.IsExpanded = true;
                        _mainTreeViewItems.Add(item);
                    }
                }

                Dictionary<string, Group> dependencyGroups = new Dictionary<string, Group>();

                LoadDenpendencies(_param.SetupConfiguration.SystemInfo.Groups, dependencyGroups, false);

                foreach (KeyValuePair<string, Group> g in dependencyGroups)
                {
                    GroupTreeViewItem item = this.AddGroupToTreeView(g.Value, null);
                    if (item != null && this.DisplayGroup(item, g.Value))
                    {
                        item.IsExpanded = true;
                        _mainTreeViewItems.Add(item);
                    }
                }

                if (_installedServices != null && _installedServices.InstalledServices != null && _installedServices.InstalledServices.Count > 0)
                    _mainTreeViewItems.Add(_installedServices);

                if (_param != null)
                    this.LoadParameterDatabaseInfo(_param);
            }
            else
            {
                _xmlOperations = null;
                _registryOperations = null;
                _mainTreeViewItems = null;
                _param = null;
            }

            return _mainTreeViewItems;
        }

        ServiceTreeViewItem RetrieveInstalledServices()
        {
            ServiceTreeViewItem installedServices = new ServiceTreeViewItem();

            IEnumerable<Group> Groups = _param.SetupConfiguration.SystemInfo.Groups.SelectDeep(g => g.SubGroups).SelectDeep(g => g.Dependencies).Distinct(new GroupComparer());
            List<InstallWindowsService> installWindowsServices = (from g in Groups
                                                                  from a in g.Actions
                                                                  where a is InstallWindowsService && g.Installed
                                                                  select (InstallWindowsService)a).Distinct(new WindowsServiceComparer()).ToList();

            List<PSE.Deployment.SetupBase.Configuration.WindowsService> servicesConfiguration = (from w in installWindowsServices
                                                                                                 from s in w.Services
                                                                                                 select s).ToList();

            installedServices.InstalledServices = servicesConfiguration;
            return installedServices;
        }

        SaveResult SaveConfiguration()
        {
            List<Group> allGroups = _param.SetupConfiguration.SystemInfo.Groups.SelectDeep(g => g.SubGroups).SelectDeep(g => g.Dependencies).Distinct(new GroupComparer()).ToList();

            SaveResult saveResult = new SaveResult();
            bool isXmlSaved = false;
            bool isRegistrySaved = false;
            List<string> servicesWhoNeedsRestart = null;

            List<string> affectedUpdateGroups = new List<string>();

            if (_xmlOperations != null && this.Configs != null)
                isXmlSaved = _xmlOperations.Save(this.Configs, allGroups, out affectedUpdateGroups);

            if (_registryOperations != null && this.RegistryKeys != null)
                isRegistrySaved = _registryOperations.Save(this.RegistryKeys);

            if ((isXmlSaved || isRegistrySaved) && _param != null)
            {
                PSE.Deployment.Util.Serializer.Serialize(GetParameterType(), _param, _parametersFilePath);
            }

            if (_xmlOperations != null && this.Configs != null)
                _xmlOperations.DecryptTags(this.Configs);

            if (_registryOperations != null && this.RegistryKeys != null)
                _registryOperations.DecryptTags(this.RegistryKeys);

            if (isXmlSaved)
            {
                List<Group> groups = (from g1 in allGroups
                                      from g2 in affectedUpdateGroups
                                      where (g1.Install == null || g1.Install.GetValueOrDefault()) && g1.Installed
                                      where g1.Id == g2
                                      select g1).ToList();

                if (groups != null && groups.Count > 0)
                {
                    servicesWhoNeedsRestart = new List<string>();

                    foreach (Group g in groups)
                    {
                        servicesWhoNeedsRestart = this.RetrieveServicesWhoNeedsRestart(g, servicesWhoNeedsRestart);
                    }
                }
            }

            if (servicesWhoNeedsRestart != null && servicesWhoNeedsRestart.Count > 0)
            {
                saveResult.Result = SaveResultOptions.SavedWithServiceChanges;
                saveResult.ServicesWhoNeedsRestart = servicesWhoNeedsRestart;
            }
            else if (isXmlSaved || isRegistrySaved)
                saveResult.Result = SaveResultOptions.SavedWithoutServiceChanges;
            else
                saveResult.Result = SaveResultOptions.NotSaved;

            return saveResult;
        }

        List<string> RetrieveServicesWhoNeedsRestart(Group group, List<string> serviceNames)
        {
            if (group.Actions != null && group.Actions.Count > 0)
            {
                foreach (ActionBase action in group.Actions)
                {
                    if (action is InstallWindowsService)
                    {
                        InstallWindowsService ws = (InstallWindowsService)action;
                        if (ws.Services != null && ws.Services.Count > 0)
                        {
                            foreach (PSE.Deployment.SetupBase.Configuration.WindowsService s in ws.Services)
                            {
                                if (!serviceNames.Contains(s.DisplayName))
                                    serviceNames.Add(s.DisplayName);
                            }
                        }
                    }
                }
            }

            if (group.Dependencies != null && group.Dependencies.Count > 0)
            {
                foreach (Group g in group.Dependencies)
                {
                    serviceNames = this.RetrieveServicesWhoNeedsRestart(g, serviceNames);
                }
            }

            return serviceNames;
        }

        bool ValidateControls()
        {
            bool hasAtLeastOneInvalid = false;

            if (PART_contentPresenter.Child != null)
            {
                StackPanel grid = ((StackPanel)((SimpleScrollViewer)PART_contentPresenter.Child).Content);

                foreach (UIElement element in grid.Children)
                {
                    if (element is BaseSimpleTextBox)
                    {
                        BaseSimpleTextBox baseTextBox = (BaseSimpleTextBox)element;
                        if (!baseTextBox.IsValid)
                        {
                            if (!hasAtLeastOneInvalid)
                                hasAtLeastOneInvalid = true;

                            continue;
                        }
                    }
                    else if (element is PasswordTextBox)
                    {
                        PasswordTextBox pwdTextBox = (PasswordTextBox)element;
                        if (pwdTextBox.IsRequired && !pwdTextBox.IsValid)
                        {
                            if (!hasAtLeastOneInvalid)
                                hasAtLeastOneInvalid = true;

                            continue;
                        }
                    }
                    else if (element is SimpleComboBox)
                    {
                        SimpleComboBox comboBox = (SimpleComboBox)element;
                        if (comboBox.IsRequired && !comboBox.IsValid)
                        {
                            if (!hasAtLeastOneInvalid)
                                hasAtLeastOneInvalid = true;

                            continue;
                        }
                    }
                    else if (element is SimpleGroupBoxes)
                    {
                        SimpleGroupBoxes gBoxes = (SimpleGroupBoxes)element;
                        foreach (UIElement childElement in gBoxes.Children)
                        {
                            if (childElement is SimpleGroupBox)
                            {
                                Panel controlGrid = (Panel)((SimpleGroupBox)childElement).Content;
                                foreach (UIElement uiElement in controlGrid.Children)
                                {
                                    if (uiElement is BaseSimpleTextBox)
                                    {
                                        BaseSimpleTextBox baseTextBox = (BaseSimpleTextBox)uiElement;
                                        if (!baseTextBox.IsValid)
                                        {
                                            if (!hasAtLeastOneInvalid)
                                                hasAtLeastOneInvalid = true;

                                            continue;
                                        }
                                    }
                                    else if (uiElement is PasswordTextBox)
                                    {
                                        PasswordTextBox pwdTextBox = (PasswordTextBox)uiElement;
                                        if (pwdTextBox.IsRequired && !pwdTextBox.IsValid)
                                        {
                                            if (!hasAtLeastOneInvalid)
                                                hasAtLeastOneInvalid = true;

                                            continue;
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }

            return !hasAtLeastOneInvalid;
        }

        public override void OnApplyTemplate()
        {
            base.OnApplyTemplate();

            PART_LoadingPanel = base.GetTemplateChild("PART_LoadingPanel") as Grid;
            PART_ScreenTitle = base.GetTemplateChild("PART_ScreenTitle") as ScreenTitle;
            PART_mainTreeView = base.GetTemplateChild("PART_mainTreeView") as TreeView;
            PART_contentPresenter = base.GetTemplateChild("PART_contentPresenter") as Border;

            PART_mainTreeView.SelectedItemChanged += new RoutedPropertyChangedEventHandler<object>(mainTreeView_SelectedItemChanged);
            PART_mainTreeView.ItemsSource = this.RetrieveGroups();

            PART_ScreenTitle.ButtonClickEvent = new RoutedEventHandler(PART_SaveButton_Click);
        }

        protected void ChangeIcon()
        {
            MemoryStream memoryStream = new MemoryStream();
            PngBitmapDecoder pngBitmapDecoder;
            System.Drawing.Icon icon;
            Stream stream = null;

            Assembly entryAssembly = System.Reflection.Assembly.GetEntryAssembly();

            foreach (string resource in entryAssembly.GetManifestResourceNames())
            {
                if (resource.EndsWith(".ico"))
                {
                    stream = entryAssembly.GetManifestResourceStream(resource);
                    break;
                }
            }

            if (stream != null)
            {
                icon = new System.Drawing.Icon(stream);
                icon.ToBitmap().Save(memoryStream, System.Drawing.Imaging.ImageFormat.Png);

                memoryStream.Seek(0, SeekOrigin.Begin);

                pngBitmapDecoder = new PngBitmapDecoder(memoryStream, BitmapCreateOptions.None, BitmapCacheOption.Default);

                this.Icon = pngBitmapDecoder.Frames[0];
            }
        }

        protected virtual void LoadParameterDatabaseInfo(SetupParameter param)
        {
        }

        protected virtual Type GetParameterType()
        {
            return typeof(SetupParameter);
        }

        protected virtual List<SimpleComboItem> RetrieveQuery(string sqlCommand)
        {
            return new List<SimpleComboItem>();
        }

        private List<SimpleComboItem> RetrieveDataSource(List<XmlTagItemSource> source)
        {
            List<SimpleComboItem> lst = new List<SimpleComboItem>();

            foreach (XmlTagItemSource item in source)
            {
                lst.Add(new SimpleComboItem
                {
                    Item = item.Name,
                    Value = item.TagValue
                });
            }

            return lst;
        }

        #region WAITING PROCESS TEST

        void ChangeLoadingPanelVisibility(bool isVisible)
        {
            ChangedLoadingPanelVisibilityDelegate d = new ChangedLoadingPanelVisibilityDelegate(ChangedLoadingPanelVisibility);
            this.Dispatcher.Invoke(System.Windows.Threading.DispatcherPriority.Send, d, isVisible);
        }

        delegate void ChangedLoadingPanelVisibilityDelegate(bool isVisible);
        void ChangedLoadingPanelVisibility(bool isVisible)
        {
            Grid gridContent = this.GetTemplateChild("PART_LoadingPanel") as Grid;
            if (gridContent != null)
            {
                if (isVisible)
                {
                    gridContent.Visibility = Visibility.Visible;
                    BringIntoView();
                    gridContent.Focus();
                }
                else
                    gridContent.Visibility = Visibility.Collapsed;
            }
        }

        #endregion
    }

    public class SaveResult
    {
        List<string> _servicesWhoNeedsRestart;

        public SaveResultOptions Result { get; set; }
        public List<string> ServicesWhoNeedsRestart
        {
            get { return _servicesWhoNeedsRestart; }
            set { _servicesWhoNeedsRestart = value; }
        }
    }

    public enum SaveResultOptions
    {
        SavedWithoutServiceChanges,
        SavedWithServiceChanges,
        NotSaved
    }
}
